package com.pocket.insight.entity;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.pocket.insight.base.utils.StringUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述：
 *
 * @author shuize
 * @create 2024/11/29
 */
public interface Type {

    Map<TypeName, Type> TYPE_MAP    = createTypeMap();
    List<Type>          TYPES       = createType();
    List<Type>          BASIC_TYPES = createBasicType();

    static Map<TypeName, Type> createTypeMap() {
        return null;
    }

    static List<Type> createType() {
        return TYPE_MAP.values()
                .stream()
                .filter(e -> (e.getTypeName().ordinal() < TypeName.any.ordinal()))
                .collect(Collectors.toList());
    }

    static List<Type> createBasicType() {
        return TYPES
                .stream()
                .filter(t -> (t.getBasicTypeName() == t.getTypeName()))
                .collect(Collectors.toList());
    }


    static Type fromTypeName(TypeName typeName) {
        return TYPE_MAP.get(typeName);
    }

    TypeName getTypeName();

    TypeName getBasicTypeName();

    boolean valueSure(Object valueSure);

    boolean valueMaybe(Object value);

    default Object cast(Object value) {
        return this.cast(value, new TypeConfig());
    }
    default TypeName getDisplayTypeName() {
        return this.getTypeName();
    }

    Object cast(Object params, TypeConfig typeConfig);

    enum TypeName {
        bool,
        integer,
        number,
        latitude,
        longitude,
        time,
        date,
        country_name,
        country_code,
        country_alpha_2,
        country_alpha_3,
        china_province_name,
        china_province_code,
        china_province_pinyin,
        china_city_name,
        china_city_code,
        china_county_name,
        china_county_code,
        string,
        json,
        array,
        any,
        unknown,
        dataset;

        private Type self;

        public Type type() {
            if (this.self == null) {
                this.self = Type.fromTypeName(this);
            }
            return this.self;
        }
    }

    @Data
    @ToString
    @EqualsAndHashCode
    @JsonIgnoreProperties(ignoreUnknown = true, value = {})
    public static class FieldType {
        public Type.TypeName   type;
        public Type.TypeConfig config;
        public Type.TypeName   srcType;
        public int hashCode() {
            return toString().hashCode();
        }
    }


    @JsonIgnoreProperties(ignoreUnknown = true, value = {})
    public static class TypeConfig {
        public String seperator;
        public String dateFormat;
        public String parentField;
        public String dialectName;
        public String     key;
        public JSONObject formatter;

        public static class Formatter {
            public ME nullReplace;
        }

        public Formatter fetchFormatter(Type.TypeName typeName) {
            if (this.formatter == null) {
                return null;
            }
            if (typeName != null) {
                JSONObject typeJson = this.formatter.getJSONObject(typeName.name());
                if (typeJson != null) {
                    Formatter typeFormatter = JSON.parseObject(JSON.toJSONString(typeJson), Formatter.class);
                    if (typeFormatter.nullReplace != null) {
                        return typeFormatter;
                    }
                }
            }
            return JSON.parseObject(JSON.toJSONString(this.formatter), Formatter.class);
        }

        public static JSONObject getNumberDefaultFormatter() {
            JSONObject formatter = new JSONObject();
            formatter.put("decimal", Integer.valueOf(2));
            formatter.put("thousands", Boolean.valueOf(false));
            return formatter;
        }

        public String fetchDateFormat() {
            return StringUtils.isNotBlank(this.dateFormat) ? this.dateFormat : ((this.formatter != null) ? this.formatter.getString("dateFormat") : null);
        }


        public boolean equals(Object object) {
            if (this == object) {
                return true;
            }
            if (!(object instanceof TypeConfig)) {
                return false;
            }
            TypeConfig that = (TypeConfig)object;
            return (new EqualsBuilder())
                    .append(StringUtils.lowerCase(this.seperator), StringUtils.lowerCase(that.seperator))
                    .append(StringUtils.lowerCase(this.dateFormat), StringUtils.lowerCase(that.dateFormat))
                    .append(StringUtils.lowerCase(this.parentField), StringUtils.lowerCase(that.parentField))
                    .append(StringUtils.lowerCase(this.key), StringUtils.lowerCase(that.key))
                    .append(this.formatter, that.formatter)
                    .isEquals();
        }
        public int hashCode() {
            return toString().hashCode();
        }


        public String toString() {
            return "TypeConfig{seperator='" + this.seperator + "', dateFormat='" + this.dateFormat + "', parentField='" + this.parentField + "', key='" + this.key + "', formatter=" + this.formatter + "}";
        }
    }
}
